package com.xlhl.mybatisplusplus.common;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xlhl.mybatisplusplus.anno.NotSelect;
import com.xlhl.mybatisplusplus.anno.QueryType;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 继承这个接口会自动根据 {@link com.xlhl.mybatisplusplus.common.SortRequestBody#sort} 中的排序条件进行排序 与 {@link com.xlhl.mybatisplusplus.anno.QueryType} 注解表示生成 查询条件
 *
 * @param <Entity> Java 实体类
 * @author xlhl
 */
public interface QueryWrapperService<Entity extends Serializable> {

    /**
     * 构造条件查询时 忽略被 {@link NotSelect} 注解标注的字段
     *
     * @param wrapper     条件查询对象
     * @param entityClass Java 实体类 Class
     * @return 构建好的 QueryWrapper
     */
    default QueryWrapper<Entity> getQueryWrapperSelectFilterByNotSelect(QueryWrapper<Entity> wrapper, Class<Entity> entityClass) {
        Field[] fields = entityClass.getDeclaredFields();

        List<String> selectFields = new ArrayList<>(fields.length);

        for (Field field : fields) {
            field.setAccessible(true);
            NotSelect notSelect = field.getAnnotation(NotSelect.class);

            if (notSelect == null) {
                String fieldName = StrUtil.toUnderlineCase(field.getName());
                selectFields.add(fieldName);
            }
        }

        wrapper.select(selectFields);

        return wrapper;
    }

    /**
     * 构造条件查询时 忽略被 {@link NotSelect} 注解标注的字段
     *
     * @param body        请求参数
     * @param entityClass Java 实体类 Class
     * @return 构建好的 QueryWrapper
     */
    default QueryWrapper<Entity> getQueryWrapperSelectFilterByNotSelect(PageRequestBody body, Class<Entity> entityClass) {
        return getQueryWrapperSelectFilterByNotSelect(getQueryWrapper(body), entityClass);
    }

    /**
     * 获取分页查询条件
     *
     * @param body 请求体对象
     * @return 构建好的 QueryWrapper
     */
    default QueryWrapper<Entity> getQueryWrapper(PageRequestBody body) {
        return getQueryWrapperByQueryType(body);
    }

    /**
     * 获取参数中的排序条件
     *
     * @param body 排序请求对象
     * @return 构建好的 QueryWrapper
     */
    default QueryWrapper<Entity> getSortQueryWrapper(SortRequestBody body) {
        QueryWrapper<Entity> queryWrapper = new QueryWrapper<>();

        Map<String, String> sort = body.getSort();

        if (CollUtil.isEmpty(sort)) {
            //  默认使用 create_time 倒序
            queryWrapper.orderByDesc("create_time");
        } else {
            for (String key : sort.keySet()) {
                queryWrapper.orderBy(true, "ascend".equals(sort.get(key)), StrUtil.toUnderlineCase(key));
            }
        }

        return queryWrapper;
    }

    /**
     * 获取查询条件
     * 会自动把参数字段转驼峰命名
     * <p>
     * 没有被 {@link QueryType} 修饰的属性会被忽略
     *
     * @param body 请求体对象
     * @return 构建好的QueryWrapper
     */
    default QueryWrapper<Entity> getQueryWrapperByQueryType(PageRequestBody body) {
        QueryWrapper<Entity> queryWrapper = getSortQueryWrapper(body);

        Field[] fields = body.getClass().getDeclaredFields();

        for (Field field : fields) {
            field.setAccessible(true);

            QueryType queryType = field.getAnnotation(QueryType.class);

            if (queryType == null) {
                continue;
            }

            QueryType.Type type = queryType.value();
            try {
                Object value = field.get(body);
                if (ObjUtil.isNotNull(value) && ObjUtil.isNotEmpty(value)) {
                    processField(queryWrapper, field, value, type);
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        return queryWrapper;
    }

    /**
     * 字段处理
     *
     * @param queryWrapper 构建好的 QueryWrapper
     * @param field        字段
     * @param value        字段值
     * @param type         查询类型
     */
    default void processField(QueryWrapper<Entity> queryWrapper, Field field, Object value, QueryType.Type type) {
        String fieldName = StrUtil.toUnderlineCase(field.getName());
        Class<?> fieldType = field.getType();
        if (fieldType == String.class) {
            //  如果是 字符串类型 trim 去掉左右空格
            value = StrUtil.trim((String) value);
        }
        switch (type) {
            //  模糊查询
            case LIKE -> queryWrapper.like(fieldName, value);
            //  精确匹配
            case EQ -> queryWrapper.eq(fieldName, value);
            //  区间查询
            case BETWEEN -> processBetween(queryWrapper, fieldName, (List<?>) value);
            //  大于
            case GREATER_THAN -> queryWrapper.gt(fieldName, value);
            //  小于
            case LESS_THAN -> queryWrapper.lt(fieldName, value);
            //  在此之间
            case IN -> {
                if (value instanceof List<?> valueInList) {
                    queryWrapper.in(fieldName, valueInList.toArray());
                }
            }
            //  不在此之间
            case NOT_IN -> queryWrapper.notIn(fieldName, value);
            default -> {/*不做处理*/}
        }
    }

    /**
     * 处理 Between 类型
     *
     * @param queryWrapper 构建好的 QueryWrapper
     * @param fieldName    字段名
     * @param values       字段值
     */
    default void processBetween(QueryWrapper<Entity> queryWrapper, String fieldName, List<?> values) {
        values = values.stream().filter(ObjUtil::isNotNull).toList();
        if (CollUtil.isNotEmpty(values)) {
            Object left = values.get(0);
            queryWrapper.ge(ObjUtil.isNotNull(left), fieldName, left);

            if (values.size() > 1) {
                Object right = values.get(1);
                queryWrapper.le(ObjUtil.isNotNull(right), fieldName, right);
            }
        }
    }
}
